package com.util;

import java.sql.*;

public class SQLUtils
{
    private static PreparedStatement statement = null;
    private static Connection connection = null;
    /**
     * 一个带有事务回滚，和批处理功能的DML语句执行方法
     *
     * @param sqlStr 需要执行的DML语句
     * @param batches 需要用批处理来拼接语句片段集合
     * @return 返回是否全部添加成功，添加失败则回滚
     */
    public static boolean executeUpdatePreparedStatement(String sqlStr, Object[][] batches)
    {
        int[] counts = new int[batches.length];

        try {
            connection = DBSCUtils.getConn();
            //进行事务管理
            connection.setAutoCommit(false);

            //获取语句对象
            statement = connection.prepareStatement(sqlStr);

            //拼接语句对象并添加批处理
            //外层循环和维度用于添加批处理对象
            for(int i = 0; i < batches.length; i ++)
            {
                //内层循环和维度用于拼接字符串
                for(int j = 0; j < batches[i].length; j ++)
                {
                    //参数1代表第几个问号，参数2代表要拼接的对象
                    //注意参数1需要+1
                    statement.setObject(j + 1, batches[i][j]);
                }
                //添加批处理
                statement.addBatch();
            }

            //执行批处理
            counts = statement.executeBatch();

            //如果全部添加成功则提交事务
            if (!hasZero(counts))
            {
                connection.commit();
                return true;
            }


        } catch (Exception e) {
            //如果捕捉到异常则回滚
            try {

                connection.rollback();

            } catch (SQLException e1)
            {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            //最终要执行的语句:重新设回自动提交
            try {
                connection.setAutoCommit(true);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        //若没能返回则回滚视为添加失败
        try {
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 一个帮助类用于检查数组里是否包含小于等于0的数字
     *
     * @param arr 需要检查的数组
     * @return 是否包含0
     */
    private static boolean hasZero(int[] arr)
    {
        for (int i : arr)
        {
            if (i <= 0)
                return true;
        }

        return false;
    }

    /**
     * 一个封装方法用于返回查询结果集
     *
     * @param sqlStr  需要执行的语句
     * @param marks 需要拼接的问号, 如果不需要则传入null或空的数组
     * @throws SQLException SQL异常
     * @return 一个执行查询语句产生的结果集
     */
    public static ResultSet executeQueryPreparedStatement(String sqlStr, Object[] marks) throws SQLException
    {
        ResultSet resultSet = null;

        connection = DBSCUtils.getConn();
        statement = connection.prepareStatement(sqlStr);

        //检查是否有拼接的问号并执行拼接
        if(marks != null) {
            for (int i = 0; i < marks.length; i++) {
                statement.setObject(i + 1, marks[i]);
            }
        }

        resultSet = statement.executeQuery();
        System.out.println(sqlStr);
        return resultSet;
    }

    /**
     * 用于返回语句对象的方法，因为语句对象需要在外部统一关闭
     *
     * @return 当前使用的语句对象
     */
    public static Statement getStatement()
    {
        return statement;
    }

    /**
     * 用于返回连接对象的方法，因为语句对象需要在外部统一关闭
     *
     * @return 当前使用的连接对象
     */
    public static Connection getConnection()
    {
        return connection;
    }
}
